//////////////////////////////////////////////////////////////////////////////////


// This code was mostly taken from http://www.gametutorials.com
// necessary modifications, compilation and assembly was done by
// Anthony Aquilio.
//Date: July 30, 2002

//see the header file for comments and user descriptions
#include <cstring>
#include "Object3DS.h"

Object3DS::Object3DS() {

	Textures = new unsigned int[MAX_TEXTURES];

	this->SetScalar(1.0f);
	this->SetPosition(0.0f, 0.0f, 0.0f);
	this->ResetRotation();

	userDefinedRGB = false;
	this->SetMonochromeColor(1.0f, 1.0f, 1.0f);

	Model_Info.numOfObjects = 0;
	Model_Info.numOfMaterials = 0;
}

void Object3DS::Initialize(char* filename){
// Objects in the study
	// First we need to actually load the .3DS file.  We just pass in an address to
	// our t3DModel structure and the file name string we want to load ("face.3ds").

	Model_Load.Import3DS(&Model_Info, filename); // Load our .3DS file into our model structure

	// Depending on how many textures we found, load each one (Assuming .bmp, .jpg, .jpeg, .tga)
	// If you want to load other files than those, you will need to adjust CreateTexture().

	// Below, we go through all of the materials and check if they have a texture map to load.
	// Otherwise, the material just holds the color information and we don't need to load a texture.

	// Go through all the materials

	for(int i = 0; i < Model_Info.numOfMaterials; i++)
	{
		// Check to see if there is a file name to load in this material
		if(strlen(Model_Info.pMaterials[i].strFile) > 0)
		{
//********************************************************************************
//Use this cout statement to find out if a texture file is needed by an 3DS object
//for proper rednering

//	cout <<" *****\n" <<
//		Model_Info.pMaterials[i].strFile
//			<< " loading for use with for " << filename << endl;
//********************************************************************************
			// Use the name of the texture file to load the bitmap, with a texture ID (i).
			// We pass in our global texture array, the name of the texture, and an ID to reference it.
			CreateTexture(Textures, Model_Info.pMaterials[i].strFile, i);
		}

		// Set the texture ID for this material
		Model_Info.pMaterials[i].texureId = i;
	}
}

void Object3DS::Render(){

	glPushMatrix();

	glTranslatef(xPosition, yPosition, zPosition);
	//turn the coordinate space to rotate the object
			glRotatef(xRotation, 1.0f, 0.0f, 0.0f);
			glRotatef(yRotation, 0.0f, 1.0f, 0.0f);
			glRotatef(zRotation, 0.0f, 0.0f, 1.0f);

	this->LocalRender();

		//turn the coordinate space back to the orignal orientation
			glRotatef((360.0f - xRotation), 1.0f, 0.0f, 0.0f);
			glRotatef((360.0f - yRotation), 0.0f, 1.0f, 0.0f);
			glRotatef((360.0f - zRotation), 0.0f, 0.0f, 1.0f);

		//Move the drawing context back to the starting position
		glTranslatef(-1.0f * xPosition, -1.0f * yPosition, -1.0f * zPosition);
	glPopMatrix();
}

void Object3DS::LocalRender(){
	// Since we know how many objects our model has, go through each of them.
	for(int i = 0; i < Model_Info.numOfObjects; i++)
	{
		// Make sure we have valid objects just in case. (size() is in the vector class)
		if(Model_Info.pObject.size() <= 0) break;

		// Get the current object that we are displaying
		t3DObject *pObject = &Model_Info.pObject[i];

		// Check to see if this object has a texture map, if so bind the texture to it.
		if(pObject->bHasTexture) {

			// Turn on texture mapping and turn off color
			glEnable(GL_TEXTURE_2D);

			// Reset the color to white
			glColor3f(1.0f, 1.0f, 1.0f);

			// Bind the texture map to the object by it's materialID
			glBindTexture(GL_TEXTURE_2D, Textures[pObject->materialID]);
		} else {

			// Turn off texture mapping and turn on color
			glDisable(GL_TEXTURE_2D);

			// Reset the color to white
			glColor3f(1.0f, 1.0f, 1.0f);
		}

		glBegin(GL_TRIANGLES);					// Begin drawing with our selected mode (triangles or lines)
			// Go through all of the faces (polygons) of the object and draw them
			for(int j = 0; j < pObject->numOfFaces; j++)
			{
				glPushMatrix();

				// Go through each corner of the triangle and draw it.
				for(int whichVertex = 0; whichVertex < 3; whichVertex++)
				{
					// Get the index for each point of the face
					int index = pObject->pFaces[j].vertIndex[whichVertex];

					// Give OpenGL the normal for this vertex.
					glNormal3f(pObject->pNormals[ index ].x, pObject->pNormals[ index ].y, pObject->pNormals[ index ].z);

					// If the object has a texture associated with it, give it a texture coordinate.
					if(pObject->bHasTexture) {

						// Make sure there was a UVW map applied to the object or else it won't have tex coords.
						if(pObject->pTexVerts) {
							glTexCoord2f(pObject->pTexVerts[ index ].x, pObject->pTexVerts[ index ].y);
						}
					} else {

						// Make sure there is a valid material/color assigned to this object.
						// You should always at least assign a material color to an object,
						// but just in case we want to check the size of the material list.
						// if the size is at least one, and the material ID != -1,
						// then we have a valid material.
						if(Model_Info.pMaterials.size() && pObject->materialID >= 0)
						{
							// Get and set the color that the object is, since it must not have a texture
							BYTE *pColor = Model_Info.pMaterials[pObject->materialID].color;

							// Assign the current color to this model
							glColor3ub(pColor[0], pColor[1], pColor[2]);
						}
					}

					if(userDefinedRGB) { glColor3f(R, G, B); }

					// Pass in the current vertex of the object (Corner of current face)
					glVertex3f(
						pObject->pVerts[ index ].x * scalar,// + xPosition,
						pObject->pVerts[ index ].y * scalar, // + yPosition,
						pObject->pVerts[ index ].z * scalar);// + zPosition);
				}
				glPopMatrix();
			}
		glEnd();

	}// End the drawing

}

void Object3DS::SetPosition(GLfloat x, GLfloat y, GLfloat z) {

	xPosition = x;
	yPosition = y;
	zPosition = z;

}

void Object3DS::Rotate(GLfloat x, GLfloat y, GLfloat z) {

	this->ResetRotation();

	xRotation = x + xRotation;
	yRotation = y + yRotation;
	zRotation = z + zRotation;

}

void Object3DS::ResetRotation() {

	xRotation = 0.0f;
	yRotation = 0.0f;
	zRotation = 0.0f;

}

void Object3DS::SetScalar(GLfloat Scalar)
{
	if(Scalar < 0.0f) {scalar = 1.0f; }
	else { scalar = Scalar;}
}

void Object3DS::SetMonochromeColor(GLfloat red, GLfloat green, GLfloat blue) {

	R = red;
	G = green;
	B = blue;
}

void Object3DS::UseMonochrome(bool flag) { userDefinedRGB = flag; }
